package com.sun.electric.compression.api;

import java.io.IOException;
import java.util.concurrent.Callable;

import com.sun.electric.compression.bzip2.BZip2BitOutputStream;
import com.sun.electric.compression.bzip2.BZip2BlockCompressor;
import com.sun.electric.compression.bzip2.BZip2DivSufSort;
import com.sun.electric.compression.bzip2.BZip2HuffmanStageEncoder;
import com.sun.electric.compression.bzip2.BZip2MTFAndRLE2StageEncoder;

/**
 * @see BZip2BlockCompressor
 * @author Daniel.Schmidt
 */
public class BZIP2BlockCompressorJava extends BZip2BlockCompressor implements
		Callable<BZIP2BlockCompressorJava> {

	/* The huffman encoder containing the preprocessed block data */
	private BZip2HuffmanStageEncoder huffmanEncoder;
	/* The CRC of the current block header */
	private int headerCRC = 0;
	/* The starting point of the bwt */
	private int bwtStartPointer = 0;

	public BZIP2BlockCompressorJava(BZip2BitOutputStream bitOutputStream,
			int blockSize) {
		super(bitOutputStream, blockSize);
	}

	/**
	 * Preprocesses the block data, initializes the huffman encoder and stores
	 * all informations that shall be written in the file.
	 */
	public BZIP2BlockCompressorJava call() {

		BZIP2BlockCompressorJava info = null;

		if (!isEmpty()) {

			// If an RLE run is in progress, write it out
			if (this.rleLength > 0) {
				writeRun(this.rleCurrentValue & 0xff, this.rleLength);
			}

			// Apply a one byte block wrap required by the BWT implementation
			this.block[this.blockLength] = this.block[0];

			// Perform the Burrows Wheeler Transform
			BZip2DivSufSort divSufSort = new BZip2DivSufSort(this.block,
					this.bwtBlock, this.blockLength);
			bwtStartPointer = divSufSort.bwt();

			headerCRC = this.crc.getCRC();

			// Perform the Move To Front Transform and Run-Length Encoding[2]
			// stages
			BZip2MTFAndRLE2StageEncoder mtfEncoder = new BZip2MTFAndRLE2StageEncoder(
					this.bwtBlock, this.blockLength, this.blockValuesPresent);
			mtfEncoder.encode();

			// Perform the Huffman Encoding stage and write out the encoded data
			huffmanEncoder = new BZip2HuffmanStageEncoder(this.bitOutputStream,
					mtfEncoder.getMtfBlock(), mtfEncoder.getMtfLength(),
					mtfEncoder.getMtfAlphabetSize(),
					mtfEncoder.getMtfSymbolFrequencies());

			// Encodes the data with the huffman encoding.
			// Notice: the encoded data isn't written to the file yet.
			try {
				huffmanEncoder.encode();
			} catch (IOException e) {
				
				e.printStackTrace();
			}
			info = this;
		}
		return info;
	}

	public int getHeaderCRC() {
		return headerCRC;
	}

	public int getBwtStartPointer() {
		return bwtStartPointer;
	}

	public BZip2HuffmanStageEncoder getEncoder() {
		return huffmanEncoder;
	}
}